home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / mint / netlib / lib / rquery.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-27  |  8.7 KB  |  295 lines

  1. /*
  2.  * Adopted to Mint-Net 1994, Kay Roemer
  3.  */
  4.  
  5. /*
  6.  * Copyright (c) 1988 Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37.  
  38. #if defined(LIBC_SCCS) && !defined(lint)
  39. static char sccsid[] = "@(#)res_query.c    5.11 (Berkeley) 3/6/91";
  40. #endif /* LIBC_SCCS and not lint */
  41.  
  42. #include "socklib.h"
  43. #include <sys/param.h>
  44. #include <netinet/in.h>
  45. #include <arpa/inet.h>
  46. #include <arpa/nameser.h>
  47. #include <netdb.h>
  48. #include <resolv.h>
  49. #include <stdio.h>
  50. #include <ctype.h>
  51. #include <errno.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54.  
  55. #ifdef __MINT__
  56. #define strcasecmp(a,b)    stricmp(a,b)
  57. #endif
  58.  
  59. #if PACKETSZ > 1024
  60. #define MAXPACKET    PACKETSZ
  61. #else
  62. #define MAXPACKET    1024
  63. #endif
  64.  
  65. int h_errno;
  66.  
  67. /*
  68.  * Formulate a normal query, send, and await answer.
  69.  * Returned answer is placed in supplied buffer "answer".
  70.  * Perform preliminary check of answer, returning success only
  71.  * if no error is indicated and the answer count is nonzero.
  72.  * Return the size of the response on success, -1 on error.
  73.  * Error number is left in h_errno.
  74.  * Caller must parse answer and determine whether it answers the question.
  75.  */
  76. int
  77. res_query(name, class, type, answer, anslen)
  78.     const char *name;        /* domain name */
  79.     int class, type;    /* class and type of query */
  80.     u_char *answer;        /* buffer to put answer */
  81.     int anslen;        /* size of answer buffer */
  82. {
  83.     char buf[MAXPACKET];
  84.     HEADER *hp;
  85.     int n;
  86.  
  87.     if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  88.         return (-1);
  89. #ifdef DEBUG
  90.     if (_res.options & RES_DEBUG)
  91.         printf("res_query(%s, %d, %d)\n", name, class, type);
  92. #endif
  93.     n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL,
  94.         buf, sizeof(buf));
  95.  
  96.     if (n <= 0) {
  97. #ifdef DEBUG
  98.         if (_res.options & RES_DEBUG)
  99.             printf("res_query: mkquery failed\n");
  100. #endif
  101.         h_errno = NO_RECOVERY;
  102.         return (n);
  103.     }
  104.     n = res_send(buf, n, (char *)answer, anslen);
  105.     if (n < 0) {
  106. #ifdef DEBUG
  107.         if (_res.options & RES_DEBUG)
  108.             printf("res_query: send error\n");
  109. #endif
  110.         h_errno = TRY_AGAIN;
  111.         return(n);
  112.     }
  113.  
  114.     hp = (HEADER *) answer;
  115.     if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
  116. #ifdef DEBUG
  117.         if (_res.options & RES_DEBUG)
  118.             printf("rcode = %d, ancount=%d\n", hp->rcode,
  119.                 ntohs(hp->ancount));
  120. #endif
  121.         switch (hp->rcode) {
  122.             case NXDOMAIN:
  123.                 h_errno = HOST_NOT_FOUND;
  124.                 break;
  125.             case SERVFAIL:
  126.                 h_errno = TRY_AGAIN;
  127.                 break;
  128.             case NOERROR:
  129.                 h_errno = NO_DATA;
  130.                 break;
  131.             case FORMERR:
  132.             case NOTIMP:
  133.             case REFUSED:
  134.             default:
  135.                 h_errno = NO_RECOVERY;
  136.                 break;
  137.         }
  138.         return (-1);
  139.     }
  140.     return(n);
  141. }
  142.  
  143. /*
  144.  * Formulate a normal query, send, and retrieve answer in supplied buffer.
  145.  * Return the size of the response on success, -1 on error.
  146.  * If enabled, implement search rules until answer or unrecoverable failure
  147.  * is detected.  Error number is left in h_errno.
  148.  * Only useful for queries in the same name hierarchy as the local host
  149.  * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
  150.  */
  151. int
  152. res_search(name, class, type, answer, anslen)
  153.     char *name;        /* domain name */
  154.     int class, type;    /* class and type of query */
  155.     u_char *answer;        /* buffer to put answer */
  156.     int anslen;        /* size of answer */
  157. {
  158.     register char *cp, **domain;
  159.      int n, ret, got_nodata = 0;
  160.     char *__hostalias();
  161.  
  162.     if ((_res.options & RES_INIT) == 0 && res_init() == -1)
  163.         return (-1);
  164.  
  165.     errno = 0;
  166.     h_errno = HOST_NOT_FOUND;        /* default, if we never query */
  167.     for (cp = name, n = 0; *cp; cp++)
  168.         if (*cp == '.')
  169.             n++;
  170.     if (n == 0 && (cp = __hostalias(name)))
  171.         return (res_query(cp, class, type, answer, anslen));
  172.  
  173.     /*
  174.      * We do at least one level of search if
  175.      *    - there is no dot and RES_DEFNAME is set, or
  176.      *    - there is at least one dot, there is no trailing dot,
  177.      *      and RES_DNSRCH is set.
  178.      */
  179.     if ((n == 0 && _res.options & RES_DEFNAMES) ||
  180.        (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
  181.          for (domain = _res.dnsrch; *domain; domain++) {
  182.         ret = res_querydomain(name, *domain, class, type,
  183.             answer, anslen);
  184.         if (ret > 0)
  185.             return (ret);
  186.         /*
  187.          * If no server present, give up.
  188.          * If name isn't found in this domain,
  189.          * keep trying higher domains in the search list
  190.          * (if that's enabled).
  191.          * On a NO_DATA error, keep trying, otherwise
  192.          * a wildcard entry of another type could keep us
  193.          * from finding this entry higher in the domain.
  194.          * If we get some other error (negative answer or
  195.          * server failure), then stop searching up,
  196.          * but try the input name below in case it's fully-qualified.
  197.          */
  198.         if (errno == ECONNREFUSED) {
  199.             h_errno = TRY_AGAIN;
  200.             return (-1);
  201.         }
  202.         if (h_errno == NO_DATA)
  203.             got_nodata++;
  204.         if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
  205.             (_res.options & RES_DNSRCH) == 0)
  206.             break;
  207.     }
  208.     /*
  209.      * If the search/default failed, try the name as fully-qualified,
  210.      * but only if it contained at least one dot (even trailing).
  211.      * This is purely a heuristic; we assume that any reasonable query
  212.      * about a top-level domain (for servers, SOA, etc) will not use
  213.      * res_search.
  214.      */
  215.     if (n && (ret = res_querydomain(name, (char *)NULL, class, type,
  216.         answer, anslen)) > 0)
  217.         return (ret);
  218.     if (got_nodata)
  219.         h_errno = NO_DATA;
  220.     return (-1);
  221. }
  222.  
  223. /*
  224.  * Perform a call on res_query on the concatenation of name and domain,
  225.  * removing a trailing dot from name if domain is NULL.
  226.  */
  227. int
  228. res_querydomain(name, domain, class, type, answer, anslen)
  229.     char *name, *domain;
  230.     int class, type;    /* class and type of query */
  231.     u_char *answer;        /* buffer to put answer */
  232.     int anslen;        /* size of answer */
  233. {
  234.     char nbuf[2*MAXDNAME+2];
  235.     char *longname = nbuf;
  236.     int n;
  237.  
  238. #ifdef DEBUG
  239.     if (_res.options & RES_DEBUG)
  240.         printf("res_querydomain(%s, %s, %d, %d)\n",
  241.             name, domain, class, type);
  242. #endif
  243.     if (domain == NULL) {
  244.         /*
  245.          * Check for trailing '.';
  246.          * copy without '.' if present.
  247.          */
  248.         n = strlen(name) - 1;
  249.         if (name[n] == '.' && n < sizeof(nbuf) - 1) {
  250.             bcopy(name, nbuf, n);
  251.             nbuf[n] = '\0';
  252.         } else
  253.             longname = name;
  254.     } else
  255.         (void)sprintf(nbuf, "%.*s.%.*s",
  256.             MAXDNAME, name, MAXDNAME, domain);
  257.  
  258.     return (res_query(longname, class, type, answer, anslen));
  259. }
  260.  
  261. char *
  262. __hostalias(name)
  263.     register const char *name;
  264. {
  265.     register char *C1, *C2;
  266.     FILE *fp;
  267.     char *file, *getenv(), *strcpy(), *strncpy();
  268.     char buf[BUFSIZ];
  269.     static char abuf[MAXDNAME];
  270.     extern int strcasecmp (const char *, const char *);
  271.     
  272.     file = getenv("HOSTALIASES");
  273.     if (file == NULL || (fp = fopen(file, "rt")) == NULL)
  274.         return (NULL);
  275.     buf[sizeof(buf) - 1] = '\0';
  276.     while (fgets(buf, sizeof(buf), fp)) {
  277.         for (C1 = buf; *C1 && !isspace(*C1); ++C1);
  278.         if (!*C1)
  279.             break;
  280.         *C1 = '\0';
  281.         if (!strcasecmp(buf, name)) {
  282.             while (isspace(*++C1));
  283.             if (!*C1)
  284.                 break;
  285.             for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
  286.             abuf[sizeof(abuf) - 1] = *C2 = '\0';
  287.             (void)strncpy(abuf, C1, sizeof(abuf) - 1);
  288.             fclose(fp);
  289.             return (abuf);
  290.         }
  291.     }
  292.     fclose(fp);
  293.     return (NULL);
  294. }
  295.